<?php

class service_l_order {

    public function init_order() {
        $obj = class_loader::new_obj('order_m_order', NULL);
        $order_id = get_order_id();
        if ($order_id === NULL) {
            if (is_user_logged_in() === FALSE) {
                $obj->guest_session_id = session_id();
                $obj->user_id = get_guest_user_id();
            } else {
                $user = get_logged_user();
                $obj->user_id = $user->id;
            }
            $order_id->site_id = service_l_core::get_current_site()->id;
            $obj->save();
            // debug_eko("order is created ".$obj->id);
        } else {
            $obj->get_by_id($order_id);
            //  debug_eko("order is loaded ".$obj->id);
        }
        return $obj;
    }

    public function delete_order($order_id) {
        $obj = class_loader::new_obj("order_m_order", NULL);
        $obj->id = $order_id;
        $obj->get();
        if ($obj->exists()) {
            $obj->delete();
        }
    }

    public function clear_order_items($order_id_or_obj) {
        $order_id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;
        $items = new order_item_m_order();
        $items->where("order_id", $order_id)->get();
        $items->delete_all();
    }

    public function update_order_subtotal($order_id_obj, $amount) {
        $obj = $this->get_object($order_id_obj);
        $obj->sub_total = $amount;
        $obj->save();
    }

    public function update_order_discount($order_id_obj, $amount) {
        $obj = $this->get_object($order_id_obj);
        $obj->discount = $amount;
        $obj->save();
    }

    public function update_order_tax($order_id_obj, $amount) {
        $obj = $this->get_object($order_id_obj);
        $obj->tax = $amount;
        $obj->save();
    }


    public function add_an_item($product_or_id,$order_or_id,$qty){
        $prod = get_object($product_or_id, "product_m_product");
        $order_obj = get_object($order_or_id, 'order_m_order');
        
        if ($prod && $order_obj){
            $oitem = new order_item_m_order();
            $oitem->order_id = $order_obj->id;
            $oitem->qty = $qty;
            $oitem->part_num = $prod->part_num;
            //$oitem->tax_class_id = $prod->tax_class_id;
            $oitem->unit_price = $prod->get_price();
            $oitem->short_desc = $prod->get_description()->short_desc;
            $oitem->save();
            return $oitem;
        }else{
            return NULL;
        }
    }
    
    public

    function update_item_qty($order_item_id,$qty,$add_with_prev=TRUE){
        $oitem = new order_item_m_order();        
        $oitem->get_by_id($order_item_id);
        if($oitem->exists()){
            if($add_with_prev){
                $oitem->qty+=$qty;
            }else{
                $oitem->qty=$qty;
            }
            return $oitem->save() ? TRUE : FALSE;
        }else{
            return NULL;
        }
    }


    public function remove_item($order_item_id_or_object){
        $oitem = get_object($order_item_id_or_object, 'order_item_m_order');
        $oitem ? $oitem->delete() ? TRUE : FALSE  : NULL;
    }
    public function item_exists($order_id,$part_num){        
        $oitem = new order_item_m_order();
        $oitem->where('order_id',$order_id)->where('part_num',$part_num)->get();
        return $oitem->exists() ? $oitem : NULL;
    }
    
    public function transfer_cart_to_order($order_id_or_obj) {
//        $order_id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;
        $order_obj = $this->get_object($order_id_or_obj);
        $this->clear_order_items($order_id_or_obj);
        $cart = service_l_cart::get_cart();
        $items = $cart->get_all_items();
        if (count($items) > 0) {
            foreach ($items as $item) {
                $this->add_an_item($item->get_product(), $order_obj, $item->qty);
            }
        }

        $this->update_order_discount($order_obj, $cart->total_discount());
        $this->update_order_tax($order_obj, $cart->total_tax());
        $this->update_order_subtotal($order_obj, $cart->total_product_price());
    }

    public function delete_address($order_id_or_obj, $address_type) {

    }

    public function delete_addresses($order_id_or_obj) {

    }

    public function mark_order($order_id_or_obj, $mark_as) {

    }

    public function delete_order_items($order_id_or_object) {

    }

    public function save_billing_address($order_id_or_obj, stdClass $address_data) {
        $order_id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;

        $add_obj = new address_m_order();
        if (!$add_obj->where('type', 'B')->where('order_id', $order_id)->get()->exists()) {
            $add_obj->order_id = $order_id;
            $add_obj->type = "B";
        }

        $add_obj->address_1 = @$address_data->billing_address_1;
        $add_obj->address_2 = @$address_data->billing_address_2;
        $add_obj->country = @$address_data->billing_country;
        $add_obj->province = @$address_data->billing_province;
        $add_obj->postal_code = @$address_data->billing_postal_code;
        $add_obj->phone_ext = @$address_data->billing_phone_ext;
        $add_obj->phone = @$address_data->billing_phone;
        $add_obj->fax = @$address_data->billing_fax;
        $add_obj->name = @$address_data->billing_name;
        return $add_obj->save();
    }

    public function get_order_items($order_id_or_obj) {
        $order = get_object($order_id_or_obj, "order_m_order");
        if ($order) {
            $items = $order->order_item_m_order->get();
            if ($items->result_count() > 0) {
                return $items;
            } else {
                return NULL;
            }
        } else {
            return NULL;
        }
    }

    public function save_shipping_address($order_id_or_obj, stdClass $address_data) {
        $order_id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;

        $add_obj = new address_m_order();
        if (!$add_obj->where('type', 'S')->where('order_id', $order_id)->get()->exists()) {
            $add_obj->order_id = $order_id;
            $add_obj->type = "S";
        }

        $add_obj->address_1 = @$address_data->shipping_address_1;
        $add_obj->address_2 = @$address_data->shipping_address_2;
        $add_obj->country = @$address_data->shipping_country;
        $add_obj->province = @$address_data->shipping_province;
        $add_obj->postal_code = @$address_data->shipping_postal_code;
        $add_obj->phone_ext = @$address_data->shipping_phone_ext;
        $add_obj->phone = @$address_data->shipping_phone;
        $add_obj->fax = @$address_data->shipping_fax;
        $add_obj->name = @$address_data->shipping_name;

        return $add_obj->save();
    }

    public function save_extra_data($order_id_or_obj, stdClass $extra_data) {
        $order_id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;
        $details_fields = new details_fields_m_order();
        $details_fields->where("type", details_fields_type_m_order::EXTRA)->get();
        if ($details_fields->result_count()) {
            foreach ($details_fields as $field) {
                $extra_obj = new extra_data_m_order();
                if (!$extra_obj->where("order_id", $order_id)->where("field_id", $field->id)->get()->exists()) {
                    $extra_obj->order_id = $order_id_or_obj;
                    $extra_obj->field_id = $field->id;
                }
                $extra_obj->field_data = $extra_data->{$field->field_name};
                $extra_obj->save();
            }
        }
    }

    public function get_order_note($order_id_or_obj) {
        
    }

    public function get_billing_address($order_id_or_obj) {
        $obj = $this->get_object($order_id_or_obj);
        if ($obj !== NULL) {
            $billing =
                            $obj->address_m_order
                            ->where("order_id", $obj->id)
                            ->where("type", details_fields_type_m_order::BILLING)
                            ->get();

            if ($billing->result_count() > 0) {
                return $billing;
            } else {
                return NULL;
            }
        }
    }

    public function get_shiping_address($order_id_or_obj) {
        $obj = $this->get_object($order_id_or_obj);
        if ($obj !== NULL) {
            $shipping =
                            $obj->address_m_order
                            ->where("order_id", $obj->id)
                            ->where("type", details_fields_type_m_order::SHIPPING)
                            ->get();

            if ($shipping->result_count() > 0) {
                return $shipping;
            } else {
                return NULL;
            }
        }
    }

    public function get_extra_data($order_id_or_obj) {
        $obj = $this->get_object($order_id_or_obj);

        if ($obj !== NULL) {
            $extra =
                            $obj->extra_data_m_order
                            ->where("order_id", $obj->id)
                            ->get();

            if ($extra->result_count() > 0) {
                return $extra;
            } else {
                return NULL;
            }
        }
    }

    public function get_all_extra_data_as_array($order_id_or_obj) {
        $id = is_object($order_id_or_obj) ? $order_id_or_obj->id : $order_id_or_obj;
        $return = array();
        $query =
                get_instance()->db->query("SELECT * FROM order_details_fields od INNER JOIN order_extra_data oe on oe.field_id  = od.id WHERE order_id='$id'");
        if ($query->num_rows()) {
            foreach ($query->result() as $row) {
                $return[$row->field_name] = $row->field_data;
            }
            return $return;
        } else {
            return array();
        }
    }

    public function get_object($order_id_object) {
        return get_object($order_id_object, "order_m_order");
    }

    public function is_order_empty($order_id_object) {
        $obj = $this->get_object($order_id_object);
        if ($obj === NULL)
            return NULL;
        else {
            return $this->get_order_items($obj) === NULL ? TRUE : FALSE;
        }
    }

    public function is_guest_order($order_id_object) {
        $obj = $this->get_object($order_id_object);
        if ($obj === NULL)
            show_error("Invalid order object or id " . __FUNCTION__);
        if (strlen($obj->guest_session_id) > 0) {
            return TRUE;
        } else {
            return FALSE;
        }
    }

    public function get_total_for_ordered_items($order_id_object){
        $obj = $this->get_object($order_id_object);
        if($obj!==NULL){
           $query =  get_instance()->db->query("SELECT SUM((qty*unit_price)) as  total_item_price FROM order_items WHERE order_id = ".$obj->id);
           if($query->num_rows()>0){
               return (float)$query->row()->total_item_price;
           }else{
               return 0.00;
           }
        }else{
            return 0.00;
        }
    }

    /**
     * List the orders that are waiting to be processed
     *
     * @param int $site_id
     * @return NULL|array of order_m_order
     */
    public function list_web_orders($site_id=NULL){
        $order = new order_m_order();
        $order->where('status',  status_m_order::COMPLETE);
        if($site_id==NULL){
            $site_id = service_l_core::get_current_site()->id;
        }
        $order->where('site_id',$site_id);
        $order->get() ;
        return $order->exists() ? $order : NULL;
    }

    /**
     * Get all discounts associated with an order
     * 
     * @param int $order_id
     * @return discount_info_m_order | NULL
     */
     
    public function get_order_discounts($order_id){
        $order_discounts = new discount_info_m_order();
        $order_discounts->get_by_order_id($order_id);
        if($order_discounts->result_count()>0){
            return $order_discounts;
        }else{
            return NULL;
        }
    }
    public function add_discount($order_id,$desc,$amount,$type="%"){
        $discount = new discount_info_m_order();
        $discount->amount           = $amount;
        $discount->order_id         = $order_id;
        $discount->discount_desc    = $desc;
        $discount->type             = $type;
        return $discount->save() ? TRUE:FALSE;
    }
    public function delete_discount_by_id($discount_id){
        $discount = new discount_info_m_order();
        $discount->get_by_id($discount_id);
        if($discount->exists()){
            return $discount->delete() ? TRUE:FALSE;
        }else{
            return NULL;
        }
    }

    /**
     * Get all extra/misc. costs associated with an order
     *
     * @param int $order_id
     * @return misc_cost_info_m_order | NULL
     */
    public function get_order_misc_costs($order_id){
        $misc_costs = new misc_cost_info_m_order();
        $misc_costs->get_by_order_id($order_id);
        if($misc_costs->result_count()>0){
            return $misc_costs;
        }else{
            return NULL;
        }
    }
    public function add_misc_cost($order_id,$desc,$amount){
        $cost = new misc_cost_info_m_order();
        $cost->amount           = $amount;
        $cost->order_id         = $order_id;
        $cost->cost_desc        = $desc;        
        return $cost->save() ? TRUE:FALSE;
    }
    public function delete_misc_cost_by_id($misc_cost_id){
        $cost = new misc_cost_info_m_order();
        $cost->get_by_id($misc_cost_id);
        if($cost->exists()){
            return $cost->delete() ? TRUE:FALSE;
        }else{
            return NULL;
        }
    }

    public function get_total_misc_cost($order_id){
        $costs = $this->get_order_misc_costs($order_id);        
        if($costs){
            $total_misc_costs = 0.00;
            foreach($costs as $c){
                $total_misc_costs+=$c->amount;
            }
            return $total_misc_costs;
        }else{
            return NULL;
        }        
    }

    /**
     * Returns order total.This do not consider discounts for the order though.
     *
     * @param int $order_id
     * @return decimal
     */
    public function calculate_order_total($order_id){
            $total= 0.00;
            //+items total
            $total+=$this->get_total_for_ordered_items($order_id);
            //+tax taotal
            $tax_service = new service_l_tax();
            $taxes =  $tax_service->get_order_tax($order_id);
            if(is_array($taxes) && count($taxes)>0){
                foreach($taxes as $t=>$amount){
                    $total+=$amount;
                }
            }
            //+shipping total
            $shipping_service  = new shipping_manager();
            $info_obj = $shipping_service->get_shipping_info($order_id);
            if($info_obj!==NULL){
                $total+=$info_obj->shipping_cost;
            }
            //+misc costs
            $total_misc_cost = $this->get_total_misc_cost($order_id);
            if($total_misc_cost!==NULL){
                $total+=$total_misc_cost;
            }
            return $total;
    }
    
    /**
     * Returns order total also considers the discounts available for the order
     * Returns (undiscounted_total  - total_discounts)
     *
     * @param int $order_id
     * @return decimal
     */
    public function calculate_order_discounted_total($order_id){
        $total_not_discounted = $this->calculate_order_total($order_id);
        $discount = $this->calculate_order_discount_by_amount($order_id, $total_not_discounted);
        return round(($total_not_discounted - $discount),2);
    }

    public function calculate_order_discount_by_amount($order_id,$order_not_discounted_total){
        $discounts_objs =  $this->get_order_discounts($order_id);
        if($discounts_objs!==NULL){
            $total_discount = 0.00;
            foreach($discounts_objs as $d){
                $total_discount+= $d->calculate_discount($order_not_discounted_total);
            }
            return $total_discount;            
        }else{
            return 0.00;
        }
    }
    
    public function get_order_discount_by_order($order_id){
        $not_discounted_total = $this->calculate_order_total($order_id);
        $discounted_total = $this->calculate_order_discount_by_amount($order_id, $not_discounted_total);
        return $discounted_total;
    }
}

?>